﻿package frEngine.manager
{
    import baseEngine.system.*;
    import com.gengine.gc.*;
    import com.gengine.resource.*;
    import com.mui.controls.*;
    import flash.display3D.*;
    import flash.events.*;
    import flash.net.*;
    import flash.utils.*;
    import frEngine.*;
    import frEngine.shader.*;

    public class Program3dManager extends Object
    {
        private var _programeById:Dictionary;
        private var _hasRegisterProgram3DMap:Dictionary;
        private var _progressHander:Function;
        private var _programMap:Dictionary;
        private var _idList:Array;
        private var _hasCreaetNum:int = 0;
        private var _startTime:Number = 0;
        private var _timeOutId:int = -1;
        private var _hasInit:Boolean = false;
        public static const instance:Program3dManager = new Program3dManager;

        public function Program3dManager()
        {
            this._programeById = new Dictionary(false);
            this._hasRegisterProgram3DMap = new Dictionary(false);
            this._programMap = new Dictionary(false);
            this._idList = [];
            return;
        }// end function

        public function init(param1:Function = null) : void
        {
            var _loc_2:ByteArray = null;
            if (this._hasInit)
            {
                return;
            }
            this._hasInit = true;
            this._progressHander = param1;
            if (Global3D.isOpenGL)
            {
                _loc_2 = ConfigManager.instance.getByteArrayByFileName("program3d_cpu.vas");
                if (_loc_2)
                {
                    this.createProgram(null, _loc_2);
                    this.preUpload();
                }
            }
            else
            {
                _loc_2 = ConfigManager.instance.getByteArrayByFileName("program3d_gpu.vas");
                if (_loc_2)
                {
                    this.createProgram(null, _loc_2);
                }
            }
            return;
        }// end function

        private function createProgram(event:Event, param2:ByteArray = null) : void
        {
            var _id:String;
            var _len:int;
            var vertextBytes:ByteArray;
            var fragmentBytes:ByteArray;
            var e:* = event;
            var bytes:* = param2;
            if (e != null)
            {
                bytes = URLLoader(e.currentTarget).data;
            }
            bytes.uncompress(CompressionAlgorithm.LZMA);
            bytes.endian = Endian.LITTLE_ENDIAN;
            bytes.position = 0;
            var pcNum:int;
            do
            {
                
                try
                {
                    _id = bytes.readUTF();
                    _len = bytes.readUnsignedInt();
                    vertextBytes = new GByteArray();
                    vertextBytes.endian = Endian.LITTLE_ENDIAN;
                    bytes.readBytes(vertextBytes, 0, _len);
                    _len = bytes.readUnsignedInt();
                    fragmentBytes = new GByteArray();
                    fragmentBytes.endian = Endian.LITTLE_ENDIAN;
                    bytes.readBytes(fragmentBytes, 0, _len);
                    this._programMap[_id] = {vertexBytes:vertextBytes, fragBytes:fragmentBytes};
                    if (_id.indexOf("pc:") != -1)
                    {
                        pcNum = (pcNum + 1);
                    }
                    else
                    {
                        this._idList.push(_id);
                    }
                }
                catch (e:Error)
                {
                    break;
                }
            }while (bytes.bytesAvailable)
            trace("create program3d count:" + this._idList.length, ",pc count:" + pcNum);
            return;
        }// end function

        public function getProgrameID(param1:String, param2:Boolean) : String
        {
            var _loc_3:Program3dRegisterInstance = null;
            param1 = param2 ? ((param1 + 1)) : (param1 + 0);
            return param1;
        }// end function

        public function getProgram3DInstance(param1:String, param2:Boolean) : Program3dRegisterInstance
        {
            var _loc_3:Program3dRegisterInstance = null;
            var _loc_4:* = this.getProgrameID(param1, param2);
            var _loc_5:* = this._programeById[_loc_4];
            if (_loc_5 && _loc_5.length > 0)
            {
                _loc_3 = _loc_5.shift();
                return _loc_3;
            }
            _loc_3 = this._hasRegisterProgram3DMap[_loc_4];
            if (_loc_3)
            {
                return new Program3dRegisterInstance(_loc_3.programeId, _loc_3);
            }
            throw new Error("请先注册program3D:" + _loc_4);
        }// end function

        public function hasRegisterProgram3D(param1:String, param2:Boolean) : Boolean
        {
            var _loc_3:* = this.getProgrameID(param1, param2);
            return this._hasRegisterProgram3DMap[_loc_3] != null;
        }// end function

        public function registerPrograme(param1:Program3dRegisterInstance, param2:Boolean) : void
        {
            var _loc_3:* = this.getProgrameID(param1.programeId, param2);
            this._hasRegisterProgram3DMap[_loc_3] = param1;
            return;
        }// end function

        public function pushPrograme3DtoPool(param1:Program3dRegisterInstance, param2:Boolean) : void
        {
            var _loc_3:* = this.getProgrameID(param1.programeId, param2);
            var _loc_4:* = this._programeById[_loc_3];
            if (!_loc_4)
            {
                var _loc_5:* = new Array();
                this._programeById[_loc_3] = new Array();
                _loc_4 = _loc_5;
            }
            _loc_4.push(param1);
            return;
        }// end function

        public function reUpload(param1:Context3D) : void
        {
            var _loc_2:String = null;
            var _loc_3:Program3dRegisterInstance = null;
            var _loc_4:Object = null;
            var _loc_5:Program3D = null;
            for (_loc_2 in this._programMap)
            {
                
                _loc_4 = this._programMap[_loc_2];
                _loc_5 = _loc_4.program;
                if (_loc_5)
                {
                    _loc_5.dispose();
                }
                _loc_5 = param1.createProgram();
                _loc_5.upload(_loc_4.vertexBytes, _loc_4.fragBytes);
                _loc_4.program = _loc_5;
            }
            for each (_loc_3 in this._hasRegisterProgram3DMap)
            {
                
                _loc_3.reUpload();
            }
            return;
        }// end function

        public function getProgram3d(param1:String, param2:Boolean) : Object
        {
            var _loc_3:* = this.getProgrameID(param1, param2);
            var _loc_4:* = this._programMap[_loc_3];
            return _loc_4;
        }// end function

        private function preUpload() : void
        {
            if (this._idList.length > 0)
            {
                this._startTime = getTimer();
                this.nextCreate();
            }
            else
            {
                this._progressHander = null;
            }
            return;
        }// end function

        private function nextCreate() : void
        {
            var _loc_1:* = this._idList[this._hasCreaetNum];
            var _loc_5:String = this;
            var _loc_6:* = this._hasCreaetNum + 1;
            _loc_5._hasCreaetNum = _loc_6;
            var _loc_2:* = this._hasCreaetNum / this._idList.length * 100;
            var _loc_3:* = this._programMap[_loc_1];
            var _loc_4:* = _loc_3.program;
            if (!_loc_4)
            {
                _loc_4 = Global3D.scene.context.createProgram();
                _loc_4.upload(_loc_3.vertexBytes, _loc_3.fragBytes);
                _loc_3.program = _loc_4;
            }
            if (this._hasCreaetNum == this._idList.length)
            {
                this._progressHander = null;
            }
            else if (getTimer() - this._startTime > 5000)
            {
                this._startTime = getTimer();
                if (this._timeOutId != -1)
                {
                    clearTimeout(this._timeOutId);
                }
                this._timeOutId = setTimeout(this.nextCreate, 100);
            }
            else
            {
                this.nextCreate();
            }
            return;
        }// end function

        public function checkToSaveLoaderInfo() : void
        {
            var _loc_9:String = null;
            var _loc_10:Number = NaN;
            var _loc_1:* = new GByteArray();
            _loc_1.endian = Endian.LITTLE_ENDIAN;
            var _loc_2:* = new FileReference();
            var _loc_3:* = LoaderManager.instance._hasLoadSizeList;
            var _loc_4:String = "";
            var _loc_5:Number = 0;
            var _loc_6:* = LoaderManager.instance._hasLoadNameList;
            var _loc_7:* = _loc_6.length;
            var _loc_8:int = 0;
            while (_loc_8 < _loc_7)
            {
                
                _loc_9 = _loc_6[_loc_8];
                if (_loc_3[_loc_9] != null)
                {
                    _loc_10 = _loc_3[_loc_9];
                    _loc_10 = _loc_10 / 1024;
                    _loc_4 = _loc_4 + _loc_9 + "\t\t" + _loc_10 + "k\r\n";
                    _loc_5 = _loc_5 + _loc_10;
                }
                _loc_8++;
            }
            _loc_4 = _loc_4 + "\r\n\r\n" + "totalSize:" + _loc_5 + "k";
            _loc_1.writeUTFBytes(_loc_4);
            _loc_2.save(_loc_1, "loaderInfo.txt");
            return;
        }// end function

        public function checkToSaveProgram() : void
        {
            var _loc_2:Program3dRegisterInstance = null;
            var _loc_3:String = null;
            var _loc_4:ByteArray = null;
            var _loc_5:FileReference = null;
            var _loc_6:Object = null;
            var _loc_1:Boolean = false;
            for (_loc_3 in this._hasRegisterProgram3DMap)
            {
                
                _loc_2 = this._hasRegisterProgram3DMap[_loc_3];
                if (_loc_2.hasAssembler && this._programMap[_loc_3] == null)
                {
                    this._programMap[_loc_3] = {vertexBytes:_loc_2.vertexBytes, fragBytes:_loc_2.fragBytes};
                    _loc_1 = true;
                }
            }
            if (_loc_1)
            {
                _loc_4 = new GByteArray();
                _loc_4.endian = Endian.LITTLE_ENDIAN;
                _loc_5 = new FileReference();
                for (_loc_3 in this._programMap)
                {
                    
                    _loc_6 = this._programMap[_loc_3];
                    _loc_4.writeUTF(_loc_3);
                    _loc_4.writeUnsignedInt(_loc_6.vertexBytes.length);
                    _loc_4.writeBytes(_loc_6.vertexBytes);
                    _loc_4.writeUnsignedInt(_loc_6.fragBytes.length);
                    _loc_4.writeBytes(_loc_6.fragBytes);
                }
                _loc_4.compress(CompressionAlgorithm.LZMA);
                _loc_5.save(_loc_4, "program3d.vas");
            }
            else
            {
                Alert.show("不需要更新3d程序");
            }
            return;
        }// end function

        public function checkToBuilderAndUpload() : void
        {
            var _loc_4:Program3dRegisterInstance = null;
            var _loc_1:* = TimeControler.stageTime;
            var _loc_2:* = TimeControler.minFpsTime;
            if (getTimer() - _loc_1 >= _loc_2)
            {
                return;
            }
            var _loc_3:* = Global3D.isOpenGL;
            for each (_loc_4 in this._hasRegisterProgram3DMap)
            {
                
                if (_loc_4.needCheckToUpload && _loc_4.hasAssembler == false)
                {
                    _loc_4.assemblerGoOn(_loc_1);
                    if (getTimer() - _loc_1 >= _loc_2 || _loc_3)
                    {
                        break;
                    }
                }
            }
            return;
        }// end function

    }
}
